use std::path::Path;
use std::fs::File;
use std::io::Write;
use std::io::{BufRead, BufReader};
use super::sphere::Sphere;
use super::traits::Skynet;
use super::{distance, vector_unit};

pub struct Vectors<'a, T> {
    pub n: usize, // 维度
    pub name: &'a str, // 名字
    pub begin: Vec<Vec<T>>,
    pub end: Vec<Vec<T>>
}

impl<'a, T: Skynet<T>> Vectors<'a, T> {
    pub fn new(n: usize, name: &'a str) -> Vectors<'a, T> {
        return Vectors {n: n, name: name, begin: Vec::new(), end: Vec::new()};
    }
    pub fn load(&mut self, path: &Path) {
        let file = File::open(path).unwrap();
        let buf = BufReader::new(file);
        for line in buf.lines() {
            let mut p: Vec<T> = Vec::new();
            for x in line.unwrap().split_whitespace() {
                p.push(x.parse().unwrap());
            }
            let mut a: Vec<T> = Vec::new();
            let mut b: Vec<T> = Vec::new();
            let n = p.len() / 2;
            assert_eq!(n + n, p.len());
            for i in 0 .. n {
                a.push(p[i]);
                b.push(p[i + n]);
            }
            self.begin.push(a);
            self.end.push(b);
        }
    }
    pub fn bounding_sphere(&self) -> Sphere<T> {
        let mut sphere: Sphere<T> = Sphere::new(self.n);
        // 计算包围球中心
        let n: T = (self.begin.len() as f64).into();
        for x_i in &self.begin {
            for j in 0 .. self.n {
                sphere.center[j] += x_i[j] / n;
            }
        }
        // 计算包围球半径
        for x in &self.begin {
            let d = distance(x, &sphere.center);
            if sphere.radius < d {
                sphere.radius = d;
            }
        }
        return sphere;
    }
    pub fn output_model(&self) {
        assert_eq!(self.n, 3);
        let mut vectors = String::new();
        vectors += format!("#declare {}_data = union {{\n", self.name).as_str();
        for i in 0 .. self.begin.len() {
            let a = &self.begin[i];
            let b = &self.end[i];
            let mut dir: Vec<T> = Vec::new();
            for j in 0 .. a.len() {
                dir.push(b[j] - a[j]);
            }
            vector_unit(&mut dir);
            let d = distance(a, b);
            let mut c: Vec<T> = Vec::new();
            for j in 0 .. b.len() {
                c.push(b[j] + T::from(0.5) * d * dir[j]); // 箭头长度是箭杆的一半
            }
            vectors += format!("  cylinder {{<{:.6}, {:.6}, {:.6}>,\
                                <{:.6}, {:.6}, {:.6}>, line_width}}\n\
                                  cone {{<{:.6}, {:.6}, {:.6}>,\
                                  0 <{:.6}, {:.6}, {:.6}>, arrow_size}}\n",
                               a[0], a[1], a[2].inv()/* 右手系 -> 左手系 */,
                               b[0], b[1], b[2].inv(),
                               c[0], c[1], c[2].inv(),
                               b[0], b[1], b[2].inv()).as_str();
        }
        vectors += "}\n";
        let mut vectors_file =
            File::create(Path::new(format!("{}.inc", self.name).as_str())).unwrap();
        vectors_file.write_all(vectors.as_bytes()).unwrap();
        
        // 输出 Povray 场景对象
        let mut object = String::new();
        object += format!("#include \"{}.inc\"\n", self.name).as_str();
        object += "object {\n";
        object += format!("  {}_data\n", self.name).as_str();
        object += "  texture {pigment {color Gray}}\n";
        object+= "}\n\n";
        let object_path = format!("{}_object.inc", self.name);
        let mut object_file = File::create(Path::new(object_path.as_str())).unwrap();
        object_file.write_all(object.as_bytes()).unwrap();
    }
}
